package com.yc.testupload.controller;

import com.yc.testupload.util.RedisUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.Cookie;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONObject;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "checkLoginStatusServlet", value = "/check-login")
public class CheckLoginStatusServlet extends HttpServlet {

    private static final Logger logger = LogManager.getLogger(CheckLoginStatusServlet.class);
    // 线上部署的顶级域名（与LoginServlet保持一致）
    private static final String ONLINE_DOMAIN = "didaproject.com";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();

        try {
            HttpSession session = request.getSession(false);
            boolean isLoggedIn = false;
            String username = null;
            Integer userId = null;

            logger.info("开始检查登录状态，用户代理: {}", request.getHeader("User-Agent"));

            // 1. 先检查session中的登录状态，无则从Redis恢复
            if (session != null) {
                logger.info("会话存在，ID: {}", session.getId());
                if (session.getAttribute("username") != null) {
                    isLoggedIn = true;
                    username = (String) session.getAttribute("username");
                    userId = session.getAttribute("userId") != null ? (Integer) session.getAttribute("userId") : null;
                    logger.info("用户 {} 已登录（从session获取），用户ID: {}", username, userId);
                } else {
                    logger.info("会话存在但未登录，尝试从Redis恢复");
                    String redisSessionData = RedisUtil.get("session:" + session.getId());
                    if (redisSessionData != null && !redisSessionData.isEmpty()) {
                        logger.info("从Redis获取到会话数据，ID: {}", session.getId());
                        JSONObject sessionJson = new JSONObject(redisSessionData);
                        username = sessionJson.getString("username");
                        userId = sessionJson.getInt("userId");
                        String persistentLogin = sessionJson.getString("persistent_login");

                        // 恢复session属性
                        session.setAttribute("username", username);
                        session.setAttribute("userId", userId);
                        session.setAttribute("persistent_login", persistentLogin);

                        // 恢复过期时间
                        int maxInactiveInterval = "true".equals(persistentLogin) ? 7 * 24 * 60 * 60 : 30 * 60;
                        session.setMaxInactiveInterval(maxInactiveInterval);

                        isLoggedIn = true;
                        logger.info("成功从Redis恢复登录状态 - 用户名: {}, 用户ID: {}", username, userId);
                    }
                }
            } else {
                logger.info("会话不存在，尝试从Redis+Cookie恢复");
                // 从Cookie获取JSESSIONID，并处理后缀（.node0等）
                String jsessionId = null;
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if ("JSESSIONID".equals(cookie.getName())) {
                            jsessionId = cookie.getValue();
                            // 关键修复：截断JSESSIONID后缀（.node0/.node1等），确保与Redis键匹配
                            if (jsessionId.contains(".")) {
                                String originalId = jsessionId;
                                jsessionId = jsessionId.split("\\.")[0]; // 只保留核心会话ID
                                logger.info("截断JSESSIONID后缀，原始值: {}, 处理后: {}", originalId, jsessionId);
                            }
                            break;
                        }
                    }
                }

                // 用处理后的JSESSIONID查询Redis，补全之前缺失的查询逻辑
                if (jsessionId != null && !jsessionId.isEmpty()) {
                    logger.info("用处理后的JSESSIONID查询Redis: {}", jsessionId);
                    String redisSessionData = RedisUtil.get("session:" + jsessionId);
                    if (redisSessionData != null && !redisSessionData.isEmpty()) {
                        logger.info("从Redis获取到会话数据，JSESSIONID: {}", jsessionId);
                        JSONObject sessionJson = new JSONObject(redisSessionData);
                        username = sessionJson.getString("username");
                        userId = sessionJson.getInt("userId");
                        String persistentLogin = sessionJson.getString("persistent_login");

                        // 创建新会话并恢复数据
                        session = request.getSession(true);
                        session.setAttribute("username", username);
                        session.setAttribute("userId", userId);
                        session.setAttribute("persistent_login", persistentLogin);

                        // 恢复过期时间
                        int maxInactiveInterval = "true".equals(persistentLogin) ? 7 * 24 * 60 * 60 : 30 * 60;
                        session.setMaxInactiveInterval(maxInactiveInterval);

                        // 刷新JSESSIONID Cookie（同步Redis数据迁移）
                        String domain = getDomainFromRequest(request);
                        refreshSessionCookie(request, response, domain, maxInactiveInterval, jsessionId);

                        isLoggedIn = true;
                        logger.info("成功从Redis恢复登录状态（新建会话）- 用户名: {}, 用户ID: {}", username, userId);
                    } else {
                        logger.warn("Redis中未找到会话数据，JSESSIONID: {}", jsessionId);
                    }
                }
            }

            // 2. Redis恢复失败，尝试从Cookie兜底恢复
            if (!isLoggedIn) {
                logger.info("开始从Cookie中检查登录状态");
                Cookie[] cookies = request.getCookies();

                if (cookies != null) {
                    logger.info("收到 {} 个Cookie，开始详细检查每个Cookie", cookies.length);
                    // 打印所有Cookie信息（调试用）
                    for (Cookie cookie : cookies) {
                        logger.info("检测到Cookie: 名称={}, 值={}, 路径={}, 过期时间={}, HttpOnly={}, Secure={}",
                                cookie.getName(),
                                cookie.getValue(),
                                cookie.getPath(),
                                cookie.getMaxAge(),
                                cookie.isHttpOnly(),
                                cookie.getSecure());
                    }

                    String cookieUsername = null;
                    String cookieUserId = null;
                    boolean hasPersistentLogin = false;

                    // 提取登录相关Cookie
                    for (Cookie cookie : cookies) {
                        switch (cookie.getName()) {
                            case "username":
                                cookieUsername = cookie.getValue();
                                logger.info("找到登录相关Cookie - username: {}", cookieUsername);
                                break;
                            case "userId":
                                cookieUserId = cookie.getValue();
                                logger.info("找到登录相关Cookie - userId: {}", cookieUserId);
                                break;
                            case "persistent_login":
                                logger.info("找到登录相关Cookie - persistent_login: {}", cookie.getValue());
                                hasPersistentLogin = "true".equals(cookie.getValue());
                                break;
                        }
                    }

                    logger.info("Cookie检查结果 - username: {}, userId: {}, persistent_login: {}",
                            cookieUsername, cookieUserId, hasPersistentLogin);

                    // 有用户名和用户ID即尝试恢复
                    if (cookieUsername != null && cookieUserId != null) {
                        try {
                            username = cookieUsername;
                            userId = Integer.parseInt(cookieUserId);

                            // 创建新会话
                            session = request.getSession(true);
                            logger.info("创建新会话用于恢复登录，会话ID: {}", session.getId());

                            // 设置会话属性
                            session.setAttribute("username", username);
                            session.setAttribute("userId", userId);
                            session.setAttribute("persistent_login", hasPersistentLogin ? "true" : "false");

                            // 设置过期时间
                            int maxInactiveInterval = hasPersistentLogin ? 7 * 24 * 60 * 60 : 30 * 60;
                            session.setMaxInactiveInterval(maxInactiveInterval);
                            logger.info("设置会话过期时间为 {} 秒，持久登录: {}", maxInactiveInterval, hasPersistentLogin);

                            // 同步数据到Redis（确保后续部署能恢复）
                            JSONObject sessionJson = new JSONObject();
                            sessionJson.put("username", username);
                            sessionJson.put("userId", userId);
                            sessionJson.put("persistent_login", hasPersistentLogin ? "true" : "false");
                            RedisUtil.set("session:" + session.getId(), sessionJson.toString(),
                                    maxInactiveInterval);
                            logger.info("会话数据已同步到Redis，ID: {}", session.getId());

                            // 刷新Cookie过期时间（强制配置Domain和Path）
                            refreshLoginCookies(request, response, username, userId.toString(), maxInactiveInterval);

                            isLoggedIn = true;
                            logger.info("成功从Cookie恢复登录状态 - 用户名: {}, 用户ID: {}", username, userId);
                        } catch (NumberFormatException e) {
                            logger.error("从Cookie恢复登录失败: 用户ID解析错误 - userId: {}", cookieUserId, e);
                            clearLoginCookies(request, response);
                        }
                    } else {
                        if (cookieUsername == null) {
                            logger.info("无法从Cookie恢复登录: 缺少username Cookie");
                        } else if (cookieUserId == null) {
                            logger.info("无法从Cookie恢复登录: 缺少userId Cookie");
                        }
                    }
                } else {
                    logger.info("没有收到任何Cookie，无法恢复登录状态");
                }
            }

            // 构建响应结果
            StringBuilder jsonResponse = new StringBuilder();
            jsonResponse.append("{\"code\":0,\"isLoggedIn\":").append(isLoggedIn)
                    .append(",\"username\":").append(username != null ? "\"" + username + "\"" : "null")
                    .append(",\"userId\":").append(userId != null ? userId : "null")
                    .append("}");

            out.write(jsonResponse.toString());
        } catch (Exception e) {
            logger.error("检查登录状态过程中发生错误: {}", e.getMessage(), e);
            out.write("{\"code\":500,\"message\":\"系统错误，请稍后重试\",\"isLoggedIn\":false}");
        } finally {
            out.flush();
            out.close();
        }
    }

    // 刷新登录相关Cookie（强制配置Domain、Path、HttpOnly）
    private void refreshLoginCookies(HttpServletRequest request, HttpServletResponse response, String username,
            String userId, int maxAge) {
        logger.info("开始刷新登录Cookie，用户: {}, 用户ID: {}, 新过期时间: {}秒", username, userId, maxAge);
        String domain = getDomainFromRequest(request);

        // 清除旧Cookie避免冲突
        clearLoginCookiesInternal(response, domain);

        // 刷新username Cookie - 强制Path=/、Domain、HttpOnly=true
        String usernameCookieStr = String.format(
                "username=%s; Max-Age=%d; Path=/; HttpOnly=true; SameSite=Lax; Secure=false; Domain=%s",
                username, maxAge, domain);
        response.addHeader("Set-Cookie", usernameCookieStr);
        logger.info("刷新username Cookie: 路径=/, HttpOnly=true, 过期时间={}秒, 域名={}", maxAge, domain);

        // 刷新userId Cookie - 同上
        String userIdCookieStr = String.format(
                "userId=%s; Max-Age=%d; Path=/; HttpOnly=true; SameSite=Lax; Secure=false; Domain=%s",
                userId, maxAge, domain);
        response.addHeader("Set-Cookie", userIdCookieStr);
        logger.info("刷新userId Cookie: 路径=/, HttpOnly=true, 过期时间={}秒, 域名={}", maxAge, domain);

        // 刷新persistent_login Cookie - 同上
        String persistentCookieStr = String.format(
                "persistent_login=true; Max-Age=%d; Path=/; HttpOnly=true; SameSite=Lax; Secure=false; Domain=%s",
                maxAge, domain);
        response.addHeader("Set-Cookie", persistentCookieStr);
        logger.info("刷新persistent_login Cookie: 路径=/, HttpOnly=true, 过期时间={}秒, 域名={}", maxAge, domain);

        // 刷新JSESSIONID Cookie - 确保无后缀、格式规范
        refreshSessionCookie(request, response, domain, maxAge, null);
        logger.info("成功刷新所有登录Cookie，用户: {}", username);
    }

    // 清除指定登录Cookie（内部使用）
    private void clearLoginCookiesInternal(HttpServletResponse response, String domain) {
        String[] cookiesToClear = { "username", "userId", "persistent_login" };
        for (String cookieName : cookiesToClear) {
            String cookieStr = String.format("%s=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax; Secure=false; Domain=%s",
                    cookieName, domain);
            response.addHeader("Set-Cookie", cookieStr);
            logger.debug("已清除旧的{} Cookie", cookieName);
        }
    }

    // 从请求提取域名（本地自动识别，线上强制指定）
    private String getDomainFromRequest(HttpServletRequest request) {
        String serverName = request.getServerName();
        // 本地环境（localhost/IP）不设置Domain
        if (serverName.equals("localhost") || serverName.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
            logger.info("当前为本地环境，不设置Cookie Domain");
            return null;
        }
        // 线上环境强制使用配置的顶级域名
        logger.info("当前为线上环境，强制设置Cookie Domain: {}", ONLINE_DOMAIN);
        return ONLINE_DOMAIN;
    }

    // 刷新JSESSIONID Cookie（含Redis数据迁移，解决多次部署问题）
    private void refreshSessionCookie(HttpServletRequest request, HttpServletResponse response, String domain,
            int maxAge, String oldJsessionId) {
        HttpSession session = request.getSession(false);
        String newSessionId = session != null ? session.getId() : "";

        // 处理旧JSESSIONID（优先使用传入的旧ID，无则从Cookie提取）
        String finalOldJsessionId = oldJsessionId;
        if (finalOldJsessionId == null || finalOldJsessionId.isEmpty()) {
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if ("JSESSIONID".equals(cookie.getName())) {
                        finalOldJsessionId = cookie.getValue();
                        if (finalOldJsessionId.contains(".")) {
                            finalOldJsessionId = finalOldJsessionId.split("\\.")[0];
                        }
                        break;
                    }
                }
            }
        }

        // 关键修复：Redis数据迁移（旧ID -> 新ID）
        if (finalOldJsessionId != null && !finalOldJsessionId.isEmpty() && !finalOldJsessionId.equals(newSessionId)) {
            String oldRedisKey = "session:" + finalOldJsessionId;
            String redisData = RedisUtil.get(oldRedisKey);
            if (redisData != null && !redisData.isEmpty()) {
                // 将旧数据写入新会话ID的Redis键
                String newRedisKey = "session:" + newSessionId;
                RedisUtil.set(newRedisKey, redisData, maxAge);
                // 删除旧键（避免冗余数据）
                RedisUtil.del(oldRedisKey);
                logger.info("Redis会话数据迁移完成，旧ID: {}, 新ID: {}", finalOldJsessionId, newSessionId);
            }
        }

        // 强制配置：Path=/、HttpOnly=true、无后缀、Domain一致
        String jsessionIdCookieStr = String.format(
                "JSESSIONID=%s; Max-Age=%d; Path=/; HttpOnly=true; SameSite=Lax; Secure=false%s",
                newSessionId, maxAge, domain != null ? "; Domain=" + domain : "");
        response.addHeader("Set-Cookie", jsessionIdCookieStr);
        logger.info("刷新JSESSIONID Cookie: 路径=/, HttpOnly=true, 过期时间={}秒, 域名={}", maxAge,
                domain != null ? domain : "(未设置)");
    }

    // 清除所有登录相关Cookie（含JSESSIONID）
    private void clearLoginCookies(HttpServletRequest request, HttpServletResponse response) {
        logger.info("开始清除所有登录相关Cookie");
        String domain = getDomainFromRequest(request);

        // 清除核心登录Cookie
        clearLoginCookiesInternal(response, domain);

        // 清除JSESSIONID Cookie
        String jsessionIdCookieStr = String.format(
                "JSESSIONID=; Max-Age=0; Path=/; HttpOnly=true; SameSite=Lax; Secure=false; Domain=%s",
                domain);
        response.addHeader("Set-Cookie", jsessionIdCookieStr);
        logger.info("已清除JSESSIONID Cookie");
        logger.info("所有登录相关Cookie清除完成");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}